//
//  SFMovableGroupViewController.m
//  TableViewFramework
//
//  Created by 支晓辉 on 16/3/30.
//  Copyright © 2016年 wishselfly. All rights reserved.
//

#import "SFMovableGroupViewController.h"
#import "SFExpandableTableViewCell.h"
#import "SFGroupItem.h"
#import "SFMyMovableView.h"

/**
 *  生成随机数
 *
 *  @param max 随机数的最大值
 *
 */
NSInteger randomNumber(NSInteger max);

@interface SFMovableGroupViewController ()
/** 数据集中 */
@property (strong, nonatomic) NSMutableArray<SFGroup*> *tableData;
/** 开始发生可拖拽移动子视图的视图 */
@property (strong, nonatomic) SFMovableView *startMovableView;
/** 当前移动的视图的截图 */
@property (strong, nonatomic) UIImageView *currentMovableView;
/** 当前视图与原点的偏移 */
@property (assign, nonatomic) CGPoint currentMovableViewOffset;
/** 当前可拖拽移动子视图的长按手势 */
@property (weak, nonatomic) UILongPressGestureRecognizer *currentMovableViewLongPressGesture;
/** 将要移动到的目标cell */
@property (weak, nonatomic) SFExpandableTableViewCell *willMoveToCell;
/** 当前正处在的cell */
@property (weak, nonatomic) SFExpandableTableViewCell *currentCell;
/** 将要移动到的索引 */
@property (assign, nonatomic) NSInteger willMoveToIndex;
/** 发生移动事件开始的组 */
@property (weak, nonatomic) SFGroup *startGroup;
/** 从哪个组开始 */
@property (weak, nonatomic) SFGroup *fromGroup;
/** 移动开始的位置的索引 */
@property (assign, nonatomic) NSInteger fromIndex;
/** 当前正在移动的item */
@property (weak, nonatomic) SFGroupItem *currentMoveItem;
/** 当前正在移动的子视图的标签 */
@property (strong, nonatomic) id movableViewTag;
/** 结束移动的位置 */
@property (assign, nonatomic) CGRect endRect;

@end

@implementation SFMovableGroupViewController

#pragma mark - init

- (instancetype)init {
    if (self = [super init]) {
        [self initValues];
    }
    return self;
}

- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        [self initValues];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super initWithCoder:aDecoder]) {
        [self initValues];
    }
    return self;
}

#pragma mark - Life cycle

- (void)viewDidLoad {
    [super viewDidLoad];
    [self initTableView];
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Test" style:UIBarButtonItemStylePlain target:self action:@selector(tapRightButton)];
}

- (void)tapRightButton {
    for (SFExpandableTableViewCell *c in self.tableView.visibleCells) {
        NSLog(@"%lf\n%@,%@", c.customAlpha, c.groupData.expanded ? @"YES":@"NO", c.groupData ? @
              "YES":@"NO");
    }
    [self.tableView reloadData];
}

#pragma mark - Override

- (SFMovableTableViewCell *)cellFromIndexPath:(NSIndexPath *)indexPath {
    SFExpandableTableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:NSStringFromClass([SFExpandableTableViewCell class])];
    SFGroup *group                  = self.tableData[indexPath.row];
    cell.title                      = group.title;
    cell.groupData                  = group;
    return cell;
}

- (void)moveRowFromIndexPath:(NSIndexPath *)srcIndexPath toIndexPath:(NSIndexPath *)destIndexPath {
    NSInteger srcIndex = srcIndexPath.row,
              destIndex = destIndexPath.row;
    id targetObj = self.tableData[srcIndex];
    [self.tableData removeObject:targetObj];
    if (destIndex >= self.tableData.count) {
        [self.tableData addObject:targetObj];
    } else {
        [self.tableData insertObject:targetObj atIndex:destIndex];
    }
}

-  (BOOL)canMoveIndexPathFrom:(NSIndexPath *)srcPath toIndexPath:(NSIndexPath *)destPath {
    return YES;
}

- (void)movableTableViewDidAutoScroll {
    [self movableView:self.startMovableView dealWithLongPressGesture:self.currentMovableViewLongPressGesture];
}

#pragma mark - Private methods

/**
 *  初始化一些值
 */
- (void)initValues {
    self.willMoveToIndex = -1;
}

/**
 *  初始化列表视图
 */
- (void)initTableView {
    [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([SFExpandableTableViewCell class])
                                               bundle:nil]
         forCellReuseIdentifier:NSStringFromClass([SFExpandableTableViewCell class])];
    self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(dealWithLongPressGesture:)];
    gesture.numberOfTouchesRequired = 1;
    gesture.minimumPressDuration = 0.5f;
    [self.tableView addGestureRecognizer:gesture];
    self.reloadDataWhenEndMove = YES;
}

- (void)dealWithLongPressGesture:(UILongPressGestureRecognizer*)gesture {
    CGPoint globalLoc = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
    if (gesture.state == UIGestureRecognizerStateBegan) {
        for (SFExpandableTableViewCell *c in self.tableView.visibleCells) {
            CGRect globalCellRect = [self.tableView convertRect:c.frame toView:[UIApplication sharedApplication].keyWindow];
            if (CGRectContainsPoint(globalCellRect, globalLoc)) {
                SFMovableView *movableView = [c getMovableViewByPoint:globalLoc];
                if (movableView) {
                    [self movableView:movableView dealWithLongPressGesture:gesture];
                    self.currentCell = c;
                } else {
                    [gesture cancelsTouchesInView];
                }
            }
        }
    } else if (self.startMovableView) {
        [self movableView:self.startMovableView dealWithLongPressGesture:gesture];
    }
}

/**
 *  cell内的组移动的时候调用的方法
 *
 *  movableView 发生移动事件的试图
 *  @param gesture     移动事件的手势实例
 */
- (void)movableViewMoveWithGesture:(UILongPressGestureRecognizer*)gesture {
    /** 是否有匹配的cell */
    BOOL isIntersectCell = NO;
    for (SFExpandableTableViewCell *c in self.tableView.visibleCells) {
        if (!c.groupData.expanded) {    //没有展开的项忽略掉
            continue;
        }
        CGRect screenRect = [self.tableView convertRect:c.frame toView:[UIApplication sharedApplication].keyWindow];
        if (CGRectIntersectsRect(screenRect, self.currentMovableView.frame)) {
            NSInteger intersectIndex = [c intersectMovableViewRectWith:self.currentMovableView.frame
                                                            filterItem:self.fromGroup.childData[self.fromIndex]];
            if (intersectIndex >= 0) {
                self.willMoveToCell = c;
                self.willMoveToIndex = intersectIndex;
                isIntersectCell = YES;
                break;
            } else if (c.groupData.childData.count <= 0) {  //没有数据的行
                //直接插入到位第一个位置
                self.willMoveToCell = c;
                self.willMoveToIndex = 0;
                isIntersectCell = YES;
                break;
            }
        } else {    //对于没有相交的cell，结束高亮状态的显示
            [c endHighLight];
        }
    }
    if (!isIntersectCell) {
        self.willMoveToCell = nil;
        self.willMoveToIndex = -1;
    }
    
    //处理自动滑动
    CGPoint location      = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
    CGRect tableViewFrame = self.tableView.frame;
    if (CGRectIntersectsRect(tableViewFrame, self.currentMovableView.frame)) {    //首先滑动的视图必须与当前tableView相交
        if (location.y >= CGRectGetMinY(tableViewFrame) &&
            location.y <= CGRectGetMinY(tableViewFrame) + 44.f) {           //向上移动
            [self tryToAutoScroll:NO];
        } else if (location.y <= CGRectGetMaxY(tableViewFrame) &&
                   location.y >= CGRectGetMaxY(tableViewFrame) - 44.f) {    //向下移动
            [self tryToAutoScroll:YES];
        } else {
            [self stopAutoScrollTimerIfNeed];
        }
    }
}

/**
 *  结束移动的处理操作
 *
 *  @param view 发生移动事件的目的视图
 */
- (void)endMovableViewMovaWithView:(SFMovableView*)view {
    SFExpandableTableViewCell *fromCell = nil;
    //移动开始的cell还是否在可视范围内
    for (SFExpandableTableViewCell *cell in self.tableView.visibleCells) {
        if (cell.groupData == self.fromGroup) {
            fromCell = cell;
            break;
        }
    }
    [self.tableView beginUpdates];
    NSInteger destIndex = self.willMoveToIndex;
    SFExpandableTableViewCell *destCell = self.willMoveToCell;
    if (fromCell) {     //如果来源的cell在可视范围内
        if (self.willMoveToCell == fromCell) {
            [fromCell moveDataFrom:self.fromIndex
                                to:self.willMoveToIndex
                          animated:YES
                          complete:^{
                              SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                              self.endRect = [toMovableView.superview convertRect:toMovableView.frame toView:[UIApplication sharedApplication].keyWindow];
                          }
             ];
            [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
            self.currentCell = self.willMoveToCell;
            self.fromIndex = self.willMoveToIndex;
        } else {
            if (self.willMoveToCell.groupData.childData.count - 1 == self.willMoveToIndex) {
                //跨组移动从结尾进入
                self.willMoveToIndex = self.willMoveToCell.groupData.childData.count;
                destIndex = self.willMoveToIndex;
            }
            [fromCell deleteDataAt:self.fromIndex animated:YES];
            [self.willMoveToCell insertDataAt:self.willMoveToIndex
                                         data:view.item
                                     animated:YES
                                     complete:^{
                                         SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                                         self.endRect = [toMovableView.superview convertRect:toMovableView.frame toView:[UIApplication sharedApplication].keyWindow];
                                     }
             ];
            [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
            self.currentCell = self.willMoveToCell;
            //变换成当前位置，以方便以后的移动
            self.fromGroup = self.willMoveToCell.groupData;
            self.fromIndex = self.willMoveToIndex;
        }
        
        self.willMoveToIndex = -1;
        self.willMoveToCell  = nil;
    } else {            //如果来源cell不在可视范围内
        //因为来源组不在视图范围内，所以直接在数据列表中把数据移除掉就可以了
        [self.fromGroup.childData removeObject:view.item];
        if (self.willMoveToCell.groupData.childData.count - 1 == self.willMoveToIndex) {
            //跨组移动从结尾进入
            self.willMoveToIndex = self.willMoveToCell.groupData.childData.count;
            destIndex = self.willMoveToIndex;
        }
        
        //动画插入数据
        [self.willMoveToCell insertDataAt:self.willMoveToIndex
                                     data:view.item
                                 animated:YES
                                 complete:^{
                                     SFMovableView *toMovableView = [destCell movableViewAtIndex:destIndex];
                                     self.endRect = [toMovableView.superview convertRect:toMovableView.frame toView:[UIApplication sharedApplication].keyWindow];
                                 }];
        [self.willMoveToCell movableViewAtIndex:self.willMoveToIndex].isMoving = YES;
        self.currentCell = self.willMoveToCell;
        //变换成当前位置，以方便以后的移动
        self.fromGroup       = self.willMoveToCell.groupData;
        self.fromIndex       = self.willMoveToIndex;
        
        self.willMoveToIndex = -1;
        self.willMoveToCell  = nil;
    }
    [self.willMoveToCell endHighLight];
    [self.tableView endUpdates];
}

#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return self.tableData.count;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return [SFExpandableTableViewCell calcRowHeightWithGroup:self.tableData[indexPath.row]];
}

#pragma mark - UITableViewDelegate

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:NO];
}

#pragma mark - SFMovableViewDelegate

- (void)movableView:(SFMovableView *)view dealWithLongPressGesture:(UILongPressGestureRecognizer *)gesture {
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:
        {
            if (self.movableViewTag) {
                return;
            }
            self.endRect = [view.superview convertRect:view.frame toView:[UIApplication sharedApplication].keyWindow];
            self.startMovableView                   = view;
            self.currentMovableViewLongPressGesture = gesture;
            self.movableViewTag                     = view;
            self.startGroup                         = view.parent;
            CGRect targetRect                       = view.frame;
            targetRect.origin                       = CGPointZero;
            UIGraphicsBeginImageContext(targetRect.size);
            [view drawViewHierarchyInRect:targetRect afterScreenUpdates:YES];
            UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
            UIGraphicsEndImageContext();
            
            view.isMoving                           = YES;
            if (!self.currentMovableView) {
                self.currentMovableView = [[UIImageView alloc] init];
            } else if (self.currentMovableView.superview) {
                [self.currentMovableView removeFromSuperview];
            }
            
            CGPoint screenLoc = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
            self.currentMovableViewOffset = [gesture locationInView:view];
            
            self.currentMovableView.frame = CGRectMake(
                                                       screenLoc.x - self.currentMovableViewOffset.x,
                                                       screenLoc.y - self.currentMovableViewOffset.y,
                                                       CGRectGetWidth(targetRect),
                                                       CGRectGetHeight(targetRect)
                                                       );
            self.currentMovableView.image               = snapshot;
            self.currentMovableView.alpha               = 0.8f;
            self.currentMovableView.contentScaleFactor  = [UIScreen mainScreen].scale;

            self.currentMovableView.layer.shadowColor   = [UIColor blackColor].CGColor;
            self.currentMovableView.layer.shadowOffset  = CGSizeMake(5.f, 5.f);
            self.currentMovableView.layer.shadowRadius  = 5.f;
            self.currentMovableView.layer.shadowOpacity = 0.6f;

            self.fromGroup                              = view.parent;
            self.fromIndex                              = [view.parent.childData indexOfObject:view.item];
            self.currentMoveItem                        = view.item;
            [[UIApplication sharedApplication].keyWindow addSubview:self.currentMovableView];
            break;
        }
        case UIGestureRecognizerStateCancelled:
        {
            //这里我实在想不到有什么更好的方法来实现
            NSInteger iterateCount = 0;
            for (SFExpandableTableViewCell *c in self.tableView.visibleCells) {
                if (c.groupData == self.startGroup) {
                    break;
                }
                iterateCount++;
            }
            if (iterateCount == self.tableView.visibleCells.count) {    //视图是因为被移除才引发的
                //这个时候的cancel事件是因为autoScroll所引发的，因此忽略
                break;
            }
        }
        case UIGestureRecognizerStateFailed:
        case UIGestureRecognizerStateEnded:         //结束长按拖动事件
        {
            CGRect *endRectPoint = &_endRect;
            
            self.tableView.scrollEnabled = NO;
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [UIView animateWithDuration:0.2f animations:^{
                    if (CGRectEqualToRect(self.endRect, CGRectZero))return;
                    self.currentMovableView.frame = *endRectPoint;
                } completion:^(BOOL finished) {
                    [self.currentMovableView removeFromSuperview];
                    self.endRect = CGRectZero;
                    self.tableView.scrollEnabled = YES;
                    [self.currentCell movableViewAtIndex:self.fromIndex].isMoving = NO;
                }];
            });
            if (view.needToDelete) {
                [view removeFromSuperview];
                view.needToDelete = NO;
            }
            [self stopAutoScrollTimerIfNeed];
            self.movableViewTag                     = nil;
            self.startGroup                         = nil;
            self.currentMovableViewLongPressGesture = nil;
            self.startMovableView                   = nil;
            break;
        }
        case UIGestureRecognizerStateChanged:       //长按拖动中的时候
        {
            if (self.currentMovableView) {
                self.currentMovableViewLongPressGesture = gesture;
                CGPoint pos = [gesture locationInView:[UIApplication sharedApplication].keyWindow];
                pos.x -= self.currentMovableViewOffset.x;
                pos.y -= self.currentMovableViewOffset.y;
                CGRect movableViewRect = self.currentMovableView.frame;
                movableViewRect.origin = pos;
                self.currentMovableView.frame = movableViewRect;
            }
            [self movableViewMoveWithGesture:gesture];
            if (self.willMoveToIndex == -1 ||
                !self.willMoveToCell) {     //没有匹配的移动视图
                return;
            }
            
            [self endMovableViewMovaWithView:view];
            break;
        }
            
        default:
            break;
    }
}

#pragma mark - Getters

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wformat"
- (NSMutableArray<SFGroup *> *)tableData {
    
    if (!_tableData) {
        //生成假数据
        NSMutableArray *arr = [NSMutableArray array];
        for (int i = 0; i < 10; i++) {
            SFGroup *g = [[SFGroup alloc] init];
            g.expanded = YES;
            g.title = [NSString stringWithFormat:@"group %d", i];
            NSMutableArray<SFGroupItem*> *groupItems = [NSMutableArray array];
            for (NSInteger j = 0, jLen = randomNumber(5) + 1; j < jLen; j++) {
                SFGroupItem *groupItem = [[SFGroupItem alloc] init];
                groupItem.title = [NSString stringWithFormat:@"Item %d,%ld", i, j];
                [groupItems addObject:groupItem];
            }
            g.childData = groupItems;
            [arr addObject:g];
        }
        _tableData = arr;
    }
    
    return _tableData;;
}
#pragma clang diagnostic pop

@end

NSInteger randomNumber(NSInteger max) {
    u_int32_t rMax = arc4random(),
    rMin = arc4random();
    if (rMax < rMin) {//交换
        rMax ^= rMin;
        rMin ^= rMax;
        rMax ^= rMin;
    }
    
    return (NSInteger)(max * (rMin / (double)rMax));
}
